package com.nc.mem;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.net.URL;

public final class GraphClassLoader extends ClassLoader {

	public static final GraphClassLoader LOADER = new GraphClassLoader();

	static final Method DEFINE_CLASS;

	static {
		Method dClass = null;

		try {
			dClass = ClassLoader.class.getDeclaredMethod("defineClass", String.class, byte[].class, int.class, int.class);
			dClass.setAccessible(true);
		} catch (final Exception exc) {
			throw new ExceptionInInitializerError(exc);
		}

		DEFINE_CLASS = dClass;
	}

	public static Class<?> defineClass(final ClassLoader cl, final byte[] buff) {
		return defineClass(cl, buff, 0, buff.length);
	}

	public static Class<?> defineClass(final ClassLoader cl, final byte[] buff, final int off, final int len) {
		try {
			return (Class<?>) DEFINE_CLASS.invoke(cl, null, buff, off, len);
		} catch (final Exception e) {
			throw new RuntimeException(e);
		}
	}

	public static Class<?> defineClass(final ClassLoader cl, final String resource) {
		return defineClass(cl, readResource(cl.getResource(resource)));
	}

	static byte[] readResource(final URL url) {
		InputStream is = null; //

		try {
			is = url.openStream();
			int sz = is.available();
			sz = sz > 0 ? sz : 1024;
			final ByteArrayOutputStream os = new ByteArrayOutputStream(sz);

			final byte[] b = new byte[sz];

			int r = 0;
			while ((r = is.read(b)) > 0) {
				os.write(b, 0, r);
			}
			return os.toByteArray();
		} catch (final IOException e) {
			throw new RuntimeException(e);
		} finally {
			if (is != null) {
				try {
					is.close();
				} catch (final IOException e) {
					// ignore
				}
			}
		}
	}

	public Class<?> defineClass(final byte[] b) {
		return super.defineClass(null, b, 0, b.length);
	}

	public Class<?> defineClass(final String resource) {
		return defineClass(getResource(resource));
	}

	public Class<?> defineClass(final URL url) {
		return defineClass(readResource(url));
	}
}
